package com.huawei.fakedouyin.service;

import static com.huawei.fakedouyin.util.UtilKt.showToast;

import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.lifecycle.Observer;

import com.google.gson.JsonObject;
import com.huawei.fakedouyin.R;
import com.huawei.fakedouyin.data.DmItem;
import com.huawei.fakedouyin.dialog.LoginOutDialog;
import com.huawei.fakedouyin.manager.PlayManager;
import com.huawei.fakedouyin.util.ActivityUtil;
import com.huawei.fakedouyin.util.GsonUtil;
import com.huawei.fakedouyin.util.LiveDataSet;
import com.huawei.fakedouyin.util.LogUtil;
import com.huawei.fakedouyin.util.MainExecutor;
import com.huawei.fakedouyin.util.SPUtil;
import com.huawei.faketaobao.constant.IConstant;
import com.huawei.faketaobao.constant.SPConstant;
import com.huawei.faketaobao.constant.SocketMsg;


import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 备注: 后台管理Socket，全局存在，除非被干掉
 */
public class SocketService extends Service {
    private ExecutorService threadPool;
    private Socket socket;
    private OutputStream dos;
    private DataInputStream dis;
    //是否第一次连接socket
    public static boolean isFirstConnectSocket = true;
    public static boolean isRunning = false;
    public static boolean isWatch = false;
    public Set<String> socketDm = new HashSet<>();

    private int errorNum = 30;

    public static void startConnectSocket(Activity activity) {
        isRunning = true;
        Intent intent = new Intent(activity, SocketService.class);
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
            activity.startForegroundService(intent);
        } else {
            activity.startService(intent);
        }
    }


    public static void updateWatchStatus(boolean watch) {
        isWatch = watch;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        notification();
        LiveDataSet.netMessage.observeForever(netObserver);
        LiveDataSet.serviceStatus.observeForever(serviceObserve);
        LiveDataSet.watchMsg.observeForever(watchMsgObserve);
        threadPool = Executors.newCachedThreadPool();
        threadPool.execute(this::socketConnect);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }


    /**
     * 连接Socket
     */
    private synchronized void socketConnect() {
        LogUtil.Companion.getInstance().logDebug("socketConnect");
        try {
            if (socket == null) {
                socket = new Socket();
            }
            SocketAddress socAddress = new InetSocketAddress(IConstant.ip, IConstant.socketPort);
            socket.setOOBInline(true);
            socket.connect(socAddress, 2000);
            dos = socket.getOutputStream();
            dis = new DataInputStream(socket.getInputStream());
            //socket重连成功 获取直播接口 重新直播
            LiveDataSet.SocketConnectedStatus.postValue(socket.isConnected());
            LogUtil.Companion.getInstance().logDebug("Socket连接结果：" + socket.isConnected());
            if (socket.isConnected()) {
                errorNum = 30;
                threadPool.execute(() -> {
                    try {
                        socketReceiveMessage();
                    } catch (Exception e) {
                        e.printStackTrace();
                        LogUtil.Companion.getInstance().logDebug("socketConnect error:" + e);
                    }
                });
                threadPool.execute(this::sendSocketLoginMsg);
            }else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                    LogUtil.Companion.getInstance().logDebug("socketConnect error:" + ex);
                }
                errorNum--;
                if (errorNum>0){
                    socketConnect();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.Companion.getInstance().logDebug("socketConnect error:" + e);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                e.printStackTrace();
                LogUtil.Companion.getInstance().logDebug("socketConnect error:" + e);
            }
            if (socket == null || !socket.isConnected()) {
                errorNum--;
                socketConnect();
            }
        }
    }

    /**
     * 发送Socket登录成功消息
     */
    private void sendSocketLoginMsg() {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("userAccount", SPUtil.Companion.getInstance().getString(SPConstant.UserAccount, ""));
        jsonObject.addProperty("userPassword", "123456");
        jsonObject.addProperty("appType", IConstant.AppType);
        if (isFirstConnectSocket) {
            isFirstConnectSocket = false;
            jsonObject.addProperty("scene", "login");
        } else {
            jsonObject.addProperty("scene", "reconnect");
        }
        socketSendMsg(jsonObject.toString());
    }

    private void notification() {
        //8.0以上
        String channelId = getClass().getSimpleName();
        NotificationCompat.Builder builder;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_DEFAULT);
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
            builder = new NotificationCompat.Builder(this, channelId);
        } else {
            builder = new NotificationCompat.Builder(this);
        }
        builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(R.string.app_name)).setWhen(System.currentTimeMillis());
        startForeground(1003, builder.build());
    }


    /**
     * Socket开始接受消息
     */
    private synchronized void socketReceiveMessage() throws Exception {
//        if (socket == null) {
//            return;
//        }
//        InputStream inputStream;
//        inputStream = socket.getInputStream();
//        int len;
//        byte[] bytes = new byte[1024];
//        while ((len = inputStream.read(bytes)) != -1) {
//            String msg = new String(bytes, 0, len);
//            dealSocketMessage(msg);
//        }
        while (socket != null && socket.isConnected() && dis != null) {
            if (socket == null) {
                continue;
            }
            byte[] buffer = new byte[dis.available()];
            if (buffer.length != 0) {
                dis.read(buffer);
                //  String msg = new String(buffer, "UTF-8");//注意转码，不然中文会乱码。
                String msg = new String(buffer);//注意转码，不然中文会乱码。
                dealSocketMessage(msg);
            }
        }
    }

    private final Handler handler = new Handler();
    private final Runnable offlineRunnable = new Runnable() {
        @Override
        public void run() {

            threadPool.execute(() -> {
                socketClose();
                socketConnect();
                if (socket != null) {
                    if (socket.isConnected()) {
                        handler.post(() -> showToast("已连接"));
                    }
                }
            });
        }
    };


    /**
     * 网络状态监听
     */
    private final Observer<Integer> netObserver = n -> {
        switch (n) {
            case 0:
                LogUtil.Companion.getInstance().logDebug("监听到网络断开");
                handler.post(offlineRunnable);
                socketClose();
                break;
            case 1:
            case 2:
                MainExecutor.get().execute(() -> showToast("网络恢复 正在重新连接..."));
                LogUtil.Companion.getInstance().logDebug("监听到网络恢复");
                threadPool.execute(() -> {
                    socketClose();
                    socketConnect();
                });
                break;
        }
    };

    private final Observer<Boolean> serviceObserve = n -> {
        if (n) {
            this.stopSelf();
        }
    };

    /**
     * 观众进退直播间发送消息
     */
    private final Observer<String> watchMsgObserve = n -> {

        threadPool.execute(this::sendUserWatchMsg);

    };

    /**
     * 处理socket消息
     */
    private void dealSocketMessage(String msg) {
        if (TextUtils.isEmpty(msg)) {
            return;
        }
        LogUtil.Companion.getInstance().logDebug("收到Socket消息：" + msg);

        //粘包问题
        if (msg.contains("{")) {

            if (msg.contains("}{")) {
                msg = msg.replace("}{", "};{");
                String[] splits = msg.split(";");
                msg = splits[splits.length - 1];
            }

        }

        LogUtil.Companion.getInstance().logDebug("格式化后的Socket消息：" + msg);

        //如果是json数据
        if (msg.startsWith("{")) {
            DmItem socketResult = GsonUtil.gsonToBean(msg, DmItem.class);

            LogUtil.Companion.getInstance().logDebug(" start dealWithCallMsg:" + socketResult);
//            MainExecutor.get().execute(() -> dealWithCallMsg(socketResult));
            dealWithCallMsg(socketResult);
        }
    }

    private void dealWithCallMsg(DmItem socketResult) {
        LogUtil.Companion.getInstance().logDebug("socketResult ==null :" + socketResult == null);
        if (socketResult == null) return;
        LogUtil.Companion.getInstance().logDebug("RecoverCall self start1:" + socketResult.toString());
        switch (socketResult.getCmd()) {

            //收到弹幕
            case SocketMsg.receiveBarrage:

                LogUtil.Companion.getInstance().logDebug("receiveBarrage self start2:" + socketResult.toString());
                //实时弹幕
                if (!socketResult.getUserAccount().equals(SPUtil.Companion.getInstance().getString(SPConstant.UserAccount, ""))) {
                    // if (socketResult.getTag().)
                    //防止socket发送多次
                    if (socketDm.add(socketResult.toString())) {
                        MainExecutor.get().execute(() -> {
                            socketResult.setLevel(10);
                            PlayManager.getInstance().sendOneDanmu(socketResult, true, false);
                        });
                    }

                }
                break;

            //异地登录
            case SocketMsg.KickOut:
                MainExecutor.get().execute(() -> {
                    PlayManager.getInstance().onlyShowImage();
                    new LoginOutDialog(ActivityUtil.Companion.getInstance().getCurrentActivity()).show();
                });
                break;
            default:

        }

    }

    /**
     * 观众进退视频播放
     */
    private void sendUserWatchMsg() {
        JsonObject jsonObject = new JsonObject();
        if (isWatch) {
            jsonObject.addProperty("watchingShortVideo", true);
        } else {
            jsonObject.addProperty("exitShortVideo", true);

        }
        jsonObject.addProperty("userAccount", SPUtil.Companion.getInstance().getString(SPConstant.UserAccount, ""));
        jsonObject.addProperty("videoId", LiveDataSet.watchMsg.get());
        socketSendMsg(jsonObject.toString());
    }

    /**
     * 发送心跳消息
     */
    private void sendHeartBeatMsg() {
        String msg = "heartBeat";
        socketSendMsg(msg);
    }

    /**
     * 发送socket消息到服务端
     *
     * @param msg json消息
     */
    private void socketSendMsg(String msg) {
        if (socket == null || dos == null) {
            return;
        }
        LogUtil.Companion.getInstance().logDebug("发送Socket消息到服务端：" + msg);
        try {
            dos.write(msg.getBytes());
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
            LogUtil.Companion.getInstance().logDebug("发送Socket消息到服务端异常：" + e);
        }
    }


    /**
     * 关闭socket
     */
    private void socketClose() {
        if (dos != null) {
            try {
                dos.close();
                dos = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (dis != null) {
            try {
                dis.close();
                dis = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (socket != null) {
            try {
                socket.close();
                socket = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LogUtil.Companion.getInstance().logDebug("关闭Socket");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        isRunning = false;
        LogUtil.Companion.getInstance().logDebug("SocketService onDestroy");
        LiveDataSet.netMessage.removeObserver(netObserver);
        LiveDataSet.serviceStatus.removeObserver(serviceObserve);
        socketClose();
        handler.removeCallbacks(offlineRunnable);
    }
}
